package com.shph.validation;

import com.shph.validation.adapter.RuleParse;
import com.shph.validation.adapter.RuleParseAdapter;
import com.shph.validation.anno.Rule;
import com.shph.validation.exception.*;
import com.shph.validation.rule.IRule;
import com.shph.validation.rule.RuleEntity;
import com.shph.validation.rule.impl.*;
import com.shph.validation.utils.ReflectUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * 检验工具类
 */
@Slf4j
public class Validator {
    private static final Map<String, IRule> defaultRule;
    // 解析器适配器
    private static final RuleParseAdapter adapter;

    // 私有化构造方法
    private Validator() {
    }

    // 类加载的时候，初始化静态属性
    static {
        defaultRule = new HashMap<>();
        adapter = new RuleParseAdapter();
    }

    public enum Strategy {
        NULL(NullRule.class), // 元素必须为 null
        NOT_NULL(NotNullRule.class), // 元素必须不为 null
        ASSERT_TRUE(AssertTrueRule.class), // 元素必须为 true
        ASSERT_FALSE(AssertFalseRule.class), // 元素必须为 false
        MIN(MinRule.class), // 元素必须是一个数字，其值必须大于等于指定的最小值
        MAX(MaxRule.class),// 元素必须是一个数字，其值必须小于等于指定的最大值
        PAST(PastRule.class),// 元素必须是一个过去的日期
        FUTURE(FutureRule.class),// 元素必须是一个将来的日期
        PATTERN(PatternRule.class), // 元素必须符合指定的正则表达式
        EMAIL(EmailRule.class), // 元素必须符合指定的正则表达式
        NOT_EMPTY(NotEmptyRule.class); // 元素必须符合指定的正则表达式

        Class<? extends IRule> clazz;

        Strategy(Class<? extends IRule> clazz) {
            this.clazz = clazz;
        }

        public Class<? extends IRule> getRuleClass() {
            return this.clazz;
        }
    }

    /**
     * 获取指定类型的IRule，如果没有，尝试创建一个
     *
     * @param clazz
     * @return
     */
    private static IRule getRuleBean(Class<? extends IRule> clazz) {
        // 从 defaultRule 获取IRule对象
        IRule rule = defaultRule.get(clazz.getName());
        if (rule == null) {
            // 使用双重校验加锁
            synchronized (Validator.class) {
                if (rule == null) {
                    // 创建一个
                    try {
                        rule = clazz.newInstance();
                        // 创建成功后，将rule放入 defaultRule 容器，备以后复用
                        defaultRule.put(clazz.getName(), rule);
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new IRuleInstanceException("创建" + clazz.getSimpleName() + "失败！");
                    }
                }
            }
        }
        return rule;
    }

    // 1. 字符串非空校验
    public static boolean isEmpty(String value) {
        // 拿到 StringEmptyRule 校验规则
        IRule rule = Validator.getRuleBean(StringEmptyRule.class);
        return rule.test(value, null);
    }

    // 2. 集合非空校验
    public static boolean isEmpty(Collection value) {
        // 拿到 CollectionEmptyRule 校验规则
        IRule rule = Validator.getRuleBean(CollectionEmptyRule.class);
        return rule.test(value, null);
    }

    // 3. Map非空校验
    public static boolean isEmpty(Map value) {
        // 拿到 MapEmptyRule 校验规则
        IRule rule = Validator.getRuleBean(MapEmptyRule.class);
        return rule.test(value, null);
    }

    // 4. 数组非空校验
    public static boolean isEmpty(Object[] value) {
        // 拿到 ArrayEmptyRule 校验规则
        IRule rule = Validator.getRuleBean(ArrayEmptyRule.class);
        return rule.test(value, null);
    }

    // 5. 对象非空校验
    public static boolean isEmpty(Object value) {
        // 拿到 ArrayEmptyRule 校验规则
        IRule rule = Validator.getRuleBean(ObjectEmptyRule.class);
        return rule.test(value, null);
    }

    // 6. 数组自定义非空校验
    public static boolean isEmpty(Object[] value, IRule rule) {
        // 拿到自定义的校验规则
        return rule.test(value, null);
    }

    // 7. 对象自定义非空校验
    public static boolean isEmpty(Object value, IRule rule) {
        // 拿到自定义的校验规则
        return rule.test(value, null);
    }

    // 8. 数组自定义非空校验
    public static boolean isEmpty(Object[] value, Class<? extends IRule> clazz) {
        // 拿到自定义的校验规则
        IRule rule = Validator.getRuleBean(clazz);
        return rule.test(value, null);
    }

    // 9. 对象自定义非空校验
    public static boolean isEmpty(Object value, Class<? extends IRule> clazz) {
        // 拿到自定义的校验规则
        IRule rule = Validator.getRuleBean(clazz);
        return rule.test(value, null);
    }

    // 10. 校验对象
    public static boolean validObject(Object target, List<RuleEntity> ruleEntities) throws ValidFailResultException {
        // 校验对象不能是空
        if (isEmpty(target)) {
            throw new ValidObjectNotNullException();
        }

        // 校验映射规则不能为空
        if (isEmpty(ruleEntities)) {
            throw new ValidMapRuleNotNullException();
        }

        // 用具记录可用校验字段
        Map<String, IRule> availableRuleMap = new HashMap<>();

        // 定义一个map，记录校验结果
        Map<String, String> errorMap = new HashMap<>();

        // 开始解析校验规则
        for (RuleEntity entity : ruleEntities) {
            String field = entity.getFiedName();
            Object rule = entity.getRule();

            // 存储真是需要执行的 Rule
            IRule executionRule;

            // 属性值
            Object fieldValue;
            try {
                // 为空时，抛出异常
                Optional.of(field);
                Optional.of(rule);

                // 获取规则解析器 RuleParse
                RuleParse support = adapter.support(rule.getClass());
                // 获取校验规则
                executionRule = support.parse(rule);
                Optional.of(executionRule);

                availableRuleMap.put(field, executionRule);

                // 获取属性值
                fieldValue = ReflectUtils.getFieldValue(target, field);
            } catch (Exception e) {
                e.printStackTrace();
                log.error(e.getMessage());
                continue;
            }

            // 执行校验方法返回
            try {
                boolean test = executionRule.test(fieldValue, entity.getRefValue());
                if (!test) {
                    throw new ValidFailException(entity.getErrorMsg());
                }
            } catch (Exception e) {
                // 记录真是的异常信息
                String error;
                if (isEmpty(entity.getErrorMsg())) {
                    error = e.getMessage();
                } else {
                    error = entity.getErrorMsg();
                }
                log.error(error);
                errorMap.put(field, error);
            }
        }

        // 如果为空，则没有可以校验的内容
        if (isEmpty(availableRuleMap)) {
            throw new NotFoundAvailableFieldOrRule();
        }

        if (!isEmpty(errorMap)) {
            throw new ValidFailResultException(errorMap);
        }
        return true;
    }

    // 11. 注解校验
    public static boolean validObject(Object target) throws ValidFailResultException {
        // 获取注解
        Class<?> clazz = target.getClass();

        // 定义一个map，记录校验结果
        Map<String, String> errorMap = new HashMap<>();
        Field[] fields = clazz.getDeclaredFields();

        Object rule;
        IRule execution;
        Object fieldValue;

        for (Field field : fields) {
            Rule ruleAnno = field.getAnnotation(Rule.class);
            if (isEmpty(ruleAnno)) {
                continue;
            }

            String fieldName = field.getName();
            String errorMsg = ruleAnno.errorMsg();
            String refValue = ruleAnno.refValue();
            // 获取校验规则
            try {
                field.setAccessible(true);
                fieldValue = field.get(target);
                field.setAccessible(false);

                // 如果 rule 不为空或者为 IRule，则默认使用
                rule = ruleAnno.rule();
                if (isEmpty(rule) || (rule == IRule.class)) {
                    // 使用枚举策略
                    rule = ruleAnno.strategy();
                }

                // 获取规则解析器 RuleParse
                RuleParse support = adapter.support(rule.getClass());
                execution = support.parse(rule);
                Optional.of(execution);
            } catch (Exception e) {
                log.error(e.getMessage());
                continue;
            }

            try {
                // 执行校验方法
                boolean test = execution.test(fieldValue, refValue);
                if (!test) {
                    throw new ValidFailException();
                }
            } catch (ValidFailException e) {
                // 记录真是的异常信息
                String error;
                if (isEmpty(errorMsg)) {
                    error = e.getMessage();
                } else {
                    error = errorMsg;
                }
                log.error(error);
                errorMap.put(fieldName, error);
            }
        }

        if (!isEmpty(errorMap)) {
            throw new ValidFailResultException(errorMap);
        }
        return true;
    }
}
